package com.khoayang.littlefighterchaos.game;

import java.util.ArrayList;
import java.util.Random;
import org.cocos2d.layers.CCLayer;
import org.cocos2d.nodes.CCDirector;
import org.cocos2d.nodes.CCSprite;
import org.cocos2d.sound.SoundEngine;
import org.cocos2d.transitions.CCFlipYTransition;
import org.cocos2d.transitions.CCRotoZoomTransition;
import org.cocos2d.types.CGPoint;
import org.cocos2d.types.CGRect;
import org.cocos2d.types.CGSize;

import com.khoayang.littlefighterchaos.R;
import com.khoayang.littlefighterchaos.game.GamePad.KEY;
import com.khoayang.littlefighterchaos.menu.ChooseCharacterLayer;
import com.khoayang.littlefighterchaos.menu.MainMenuLayer;

import android.content.Context;
import android.util.Log;
import android.view.MotionEvent;

public class GameLayer extends CCLayer implements GamePadListener,
		AttackingObjectListener, DyingListener {

	private CharacterGame _Character;
	private ArrayList<CharacterGame> _ComputerCharacters;
	private ArrayList<AI> _ComputerAI;
	private ArrayList<AttackingObject> _AttackingObjects;
	private ArrayList<KEY> _KeyState;
	private Context _Context;
	private GameManagerContent _GameManagerContent;

	public GameLayer(Context context) {
		super();
		_Context = context;
		_GameManagerContent = GameManagerContent.Instance();

		SoundEngine.sharedEngine().preloadSound(context, R.raw.backgroundmusic);
		SoundEngine.sharedEngine().playSound(context, R.raw.backgroundmusic,
				true);

		_KeyState = new ArrayList<KEY>();
		_AttackingObjects = new ArrayList<AttackingObject>();
		_ComputerCharacters = new ArrayList<CharacterGame>();
		_ComputerAI = new ArrayList<AI>();

		String _characters[] = ChooseCharacterLayer.get_characters();
		int _teamIDs[] = ChooseCharacterLayer.get_teamIDs();

		CharacterFactory characterFactory = CharacterFactory
				.getInstance(_Context);

		_Character = characterFactory.cloneCharacterByName(_characters[0]);
		_Character.setContext(context);
		_Character.setDyingListener(this);
		CGSize winSize = CCDirector.sharedDirector().displaySize();

		_Character.set_Position(CGPoint.ccp(100f, winSize.height / 2.0f));
		_Character.set_ID(_teamIDs[0]);
		_Character.addObserverAttackingObject(this);

		_Character.runDefaultAction();
		_ComputerCharacters.add(_Character);
		addChild(_Character.get_Sprite(), 1);
		addChild(_Character.get_HPBar().get_SpriteBar());
		addChild(_Character.get_HPBar().get_SpriteFillBar());
		addChild(_Character.get_MPBar().get_SpriteBar());
		addChild(_Character.get_MPBar().get_SpriteFillBar());

		this.schedule("update");

		// init character from layer choose character
		for (int i = 1; i < 8; i++) {

			// String charName =
			// characterFactory.get_AllCharacter().get(i).get_State().get_Name();
			CharacterGame character = characterFactory
					.cloneCharacterByName(_characters[i]);
			if (character != null) {
				setRandomPosition(character);

				character.setContext(context);
				character.set_ID(_teamIDs[i]);
				character.addObserverAttackingObject(this);
				character.setDyingListener(this);

				character.runDefaultAction();
				addChild(character.get_Sprite(), 1);
				addChild(character.get_HPBar().get_SpriteBar());
				addChild(character.get_HPBar().get_SpriteFillBar());
				addChild(character.get_MPBar().get_SpriteBar());
				addChild(character.get_MPBar().get_SpriteFillBar());

				AI ai = getAIBy(MainMenuLayer._DifficultyLevel,character, _ComputerCharacters);
				_ComputerAI.add(ai);
				_ComputerCharacters.add(character);
			}
		}

		// init computer characters stage mode
		if (MainMenuLayer._isStageMode == true)
			for (int i = 0; i < characterFactory.get_AllCharacter().size() - 7; i++) {
				String charName = characterFactory.get_AllCharacter().get(i)
						.get_State().get_Name();
				CharacterGame character = characterFactory
						.cloneCharacterByName(charName);
				setRandomPosition(character);

				character.setContext(context);
				character.set_ID(2);
				character.addObserverAttackingObject(this);
				character.setDyingListener(this);

				character.runDefaultAction();
				addChild(character.get_Sprite());
				addChild(character.get_HPBar().get_SpriteBar());
				addChild(character.get_HPBar().get_SpriteFillBar());
				addChild(character.get_MPBar().get_SpriteBar());
				addChild(character.get_MPBar().get_SpriteFillBar());

				AI ai = getAIBy(MainMenuLayer._DifficultyLevel,character, _ComputerCharacters);
				_ComputerAI.add(ai);
				_ComputerCharacters.add(character);
			}
	}
	
	private AI getAIBy(int id, CharacterGame character, ArrayList<CharacterGame> otherCharacters){
		switch(id){
		case 0:
			return new DummyAI(character, otherCharacters);
		case 1:
			return new IntelligentAI(character, otherCharacters);
		}
		return null;
	}

	public void checkAndClampSpritePositionHor() {
		float xOffset = 40.0f;
		CGSize winSize = CCDirector.sharedDirector().displaySize();
		if (_Character.get_Position().x < xOffset) {
			_Character.set_Position(CGPoint.ccp(xOffset,
					_Character.get_Position().y));
		} else if (_Character.get_Position().x > winSize.width - xOffset) {
			_Character.set_Position(CGPoint.ccp(winSize.width - xOffset,
					_Character.get_Position().y));
		}
	}

	public void checkAndClampSpritePositionVer() {
		float yOffset = 40.0f;
		if (_Character.get_Position().y < yOffset) {
			_Character.set_Position(CGPoint.ccp(_Character.get_Position().x,
					yOffset));
		} else if (_Character.get_Position().y > (_GameManagerContent
				.get_SizeMap().height / 3)) {
			_Character.set_Position(CGPoint.ccp(_Character.get_Position().x,
					_GameManagerContent.get_SizeMap().height / 3));
		}
	}

	private void rollBackground() {
		float xOffset = 80.0f;
		CGPoint pos = GameScene._backgroundGame.getPosition();
		CGSize winSize = CCDirector.sharedDirector().displaySize();
		float delta1 = _Character.get_Position().x - (winSize.width - xOffset);
		if (delta1 > 0 && pos.x >= -(winSize.width * 2)) {
			for (int i = 0; i < _ComputerCharacters.size(); i++) {
				CharacterGame s = _ComputerCharacters.get(i);
				s.set_Position(CGPoint.ccp(s.get_Position().x - delta1,
						s.get_Position().y));
			}
			for (int i = 0; i < _AttackingObjects.size(); i++) {
				AttackingObject s = _AttackingObjects.get(i);
				s.set_Position(CGPoint.ccp(s.get_Position().x - delta1,
						s.get_Position().y));
			}
			_Character.set_Position(CGPoint.make(winSize.width - xOffset,
					_Character.get_Position().y));

			GameScene._backgroundGame.ChangePosition(delta1, 0);
		}
		float delta2 = _Character.get_Position().x - xOffset;
		if (delta2 < 0 && pos.x <= 0) {
			for (int i = 0; i < _ComputerCharacters.size(); i++) {
				CharacterGame s = _ComputerCharacters.get(i);
				s.set_Position(CGPoint.ccp(s.get_Position().x - delta2,
						s.get_Position().y));
			}
			for (int i = 0; i < _AttackingObjects.size(); i++) {
				AttackingObject s = _AttackingObjects.get(i);
				s.set_Position(CGPoint.ccp(s.get_Position().x - delta2,
						s.get_Position().y));
			}
			_Character.set_Position(CGPoint.make(xOffset,
					_Character.get_Position().y));

			GameScene._backgroundGame.ChangePosition(delta2, 0);

		}
	}

	private void setRandomPosition(CharacterGame character) {
		Random r = new Random();
		CGSize winSize = CCDirector.sharedDirector().winSize();
		int x = r.nextInt((int) winSize.width);
		int y = r.nextInt((int) winSize.height / 3);

		character.set_Position(CGPoint.ccp(x, y));
	}

	public void update(float dt) {

		

		// clamp and bound character player on map
		checkAndClampSpritePositionHor();
		checkAndClampSpritePositionVer();
		rollBackground();

		
		
		// update all character
		_Character.update(_KeyState);
		for (int i = 0; i < _ComputerAI.size(); i++)
			_ComputerAI.get(i).update();

		// update all attacking object
		for (int i = 0; i < _AttackingObjects.size(); i++) {
			_AttackingObjects.get(i).update();
			if (_AttackingObjects.get(i).isDied()) {
				removeChild(_AttackingObjects.get(i).get_Sprite(), true);
				_AttackingObjects.remove(_AttackingObjects.get(i));
			}
		}

		// check collision
		//AttackingObject vs AttackingObject
		for(int i=0; i<_AttackingObjects.size(); i++)
		{
			for(int j=0; j<_AttackingObjects.size(); j++)
			{
				AttackingObject attackingObjectI = _AttackingObjects.get(i);
				AttackingObject attackingObjectJ = _AttackingObjects.get(j);
				if(checkCollide(attackingObjectI.getRect(), attackingObjectJ.getRect())){
					if(attackingObjectI.get_Owner() != attackingObjectJ.get_Owner()){
						if(attackingObjectI.get_AttackValue() > attackingObjectJ.get_AttackValue()){
							attackingObjectJ.isDied(true);
						}else if(attackingObjectI.get_AttackValue() < attackingObjectJ.get_AttackValue()){
							attackingObjectI.isDied(true);
						}else{
							attackingObjectI.isDied(true);
							attackingObjectJ.isDied(true);
						}
					}	
				}
			}
		}
		
		// AttackingObject vs character
		
		for (int i = 0; i < _AttackingObjects.size(); i++) {
			AttackingObject attackingObject = _AttackingObjects.get(i);
			for (int j = 0; j < _ComputerCharacters.size(); j++) {
				CharacterGame character = _ComputerCharacters.get(j);
				if (attackingObject.get_Owner() != character.get_ID()) {
					if (checkCollide(attackingObject.getRect(),
							character.getRect())) {
						character.beHit(attackingObject);
						attackingObject.isDied(true);
					}
				}
			}
		}

		// Character vs character
		for (int i = 0; i < _ComputerCharacters.size(); i++) {
			for (int j = 0; j < _ComputerCharacters.size(); j++) {
				CharacterGame characterI = _ComputerCharacters.get(i);
				CharacterGame characterJ = _ComputerCharacters.get(j);
				if (checkCollide(characterI.getRect(),
						characterJ.getRect())
						&& characterI.get_ID() != characterJ.get_ID()) {
					if (characterI.get_State().get_CurrentSkill() instanceof AttackingSkill) {
						if (!(characterJ.get_State().get_CurrentSkill() instanceof BeHitSkill)) {
							characterJ.beHit(characterI);
						}
					}
					if (characterJ.get_State().get_CurrentSkill() instanceof AttackingSkill) {
						if (!(characterI.get_State().get_CurrentSkill() instanceof BeHitSkill)) {
							characterI.beHit(characterJ);
						}
					}
				}
			}
		}
		//_ComputerCharacters.remove(_Character);

		// set order all object
		if(_Character != null)
			_Character.setOrder();
		for (int i = 0; i < _ComputerCharacters.size(); i++) {
			if(_ComputerCharacters.get(i) != null)
				_ComputerCharacters.get(i).setOrder();
		}
		for (int i = 0; i < _AttackingObjects.size(); i++) {
			if(_AttackingObjects.get(i) != null)
				_AttackingObjects.get(i).setOrder();
		}
		
		// kiem tra thang thua
				if (checkWin()) {
					boolean a =  MainMenuLayer._isStageMode;
					if (MainMenuLayer._isStageMode == false) {
						SoundEngine.sharedEngine().pauseSound();
						CCDirector.sharedDirector().replaceScene(new CCFlipYTransition(3,
								NotifyLayer.scene("You Win!", _Context),1));
					} else {
						if (BackgoundGame.ground1
								.compareTo("background-game/ground1.png") == 0) {
							
							
							BackgoundGame.ground1 = "background-game/ground2.png";
							BackgoundGame.ground2 = "background-game/ground2.png";
							BackgoundGame.ground3 = "background-game/ground2.png";
							BackgoundGame.sky = "background-game/sky2.bmp";
							
							GameScene gameScene = new GameScene(_Context);
							CCDirector.sharedDirector().runWithScene(
									new CCRotoZoomTransition(1, gameScene));
						}
						
					}
				}
				if (checkLose()) {
					SoundEngine.sharedEngine().pauseSound();
					CCDirector.sharedDirector().replaceScene(new CCFlipYTransition(3,
							NotifyLayer.scene("You Lose!", _Context),1));
				}

	}

	public int findNearEnemy(CGPoint a, ArrayList<CGPoint> ds)
	{
		double length = 900000000;
		int target = 0;
		for(int i=0;i<ds.size();i++)
		{
			CGPoint b = ds.get(i);
			double temp = Math.pow(b.x -a.x,2) + Math.pow(b.y -a.y,2);
			if(temp <  length)
			{
				length = temp;
				target = i;
			}
		}
		return target;
	}
	
	public boolean checkWin() {
		for (int i = 0; i < _ComputerCharacters.size(); i++) {
			CharacterGame characterI = _ComputerCharacters.get(i);
			if (characterI.get_ID() != _Character.get_ID()) {
				return false;
			}
		}
		return true;
	}

	public boolean checkLose() {
		if (_Character.get_CurrentHP() == 0)
			return true;
		return false;
	}

	public void checkAndCallAction() {
		if (!_Character.is_IsSpecialAction()) {
			String currentActionName = _Character.getActionName(_KeyState);
			if (currentActionName != null) {
				_Character.startAction(currentActionName);
			} else if (_KeyState.size() > 0) {
				ArrayList<KEY> keyStateTemp = new ArrayList<GamePad.KEY>();
				keyStateTemp.add(_KeyState.get(_KeyState.size() - 1));
				_Character.resetAllActionState();
				String actionName = _Character.getActionName(keyStateTemp);
				_Character.startAction(actionName);
			}
		}
	}

	public void leftButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.LEFT);
		checkAndCallAction();
		// _Character.startAction("Walk");

	}

	public void leftButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.LEFT);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
		// _Character.stopAction("Walk");
	}

	public void rightButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.RIGHT);
		checkAndCallAction();
		// _Character.startAction("Walk");

	}

	public void rightButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.RIGHT);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
		// _Character.stopAction("Walk");
	}

	public void attackButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.ATTACK);
		checkAndCallAction();
		// _Character.startAction("Punch");
	}

	public void attackButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.ATTACK);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
		// _Character.stopAction("Punch");
	}

	public void defendButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.DEFEND);
		checkAndCallAction();
		// _Character.startAction("Defend");
	}

	public void jumpButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.JUMP);
		checkAndCallAction();
		// _Character.startJump();
	}

	public void jumpButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.JUMP);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
	}

	public void defendButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.DEFEND);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
	}

	public void upButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.UP);
		checkAndCallAction();
	}

	public void upButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.UP);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
	}

	public void downButtonDown(MotionEvent motionEvent) {
		_KeyState.add(KEY.DOWN);
		checkAndCallAction();
	}

	public void downButtonUp(MotionEvent motionEvent) {
		_KeyState.remove(KEY.DOWN);
		if (!_Character.is_IsSpecialAction())
			_Character.stopAction();
		checkAndCallAction();
	}

	public void addNewAttackingObject(AttackingObject object) {
		_AttackingObjects.add(object);
		addChild(object.get_Sprite());
	}

	public static boolean checkCollide(CGRect rect1, CGRect rect2) {
		if (CGRect.intersects(rect1, rect2)) {
			return true;
		}
		return false;
	}

	
	public static boolean checkSpriteCollide(CCSprite sprite1, CCSprite sprite2) {
		CGPoint spriteTopLeftPos = CGPoint.ccp(sprite1.getPosition().x
				- sprite1.getContentSize().width / 2, sprite1.getPosition().y
				- sprite1.getContentSize().height / 2);
		CGRect rect1 = CGRect.make(spriteTopLeftPos, sprite1.getContentSize());

		spriteTopLeftPos = CGPoint.ccp(
				sprite2.getPosition().x - sprite2.getContentSize().width / 2,
				sprite2.getPosition().y - sprite2.getContentSize().height / 2);
		CGRect rect2 = CGRect.make(spriteTopLeftPos, sprite2.getContentSize());
		return checkCollide(rect1, rect2);
	}

	@Override
	public void dyingPerform(CharacterGame character) {
		this.removeChild(character.get_Sprite(), false);
		this.removeChild(character.get_HPBar().get_SpriteBar(), false);
		this.removeChild(character.get_MPBar().get_SpriteBar(), false);
		this.removeChild(character.get_HPBar().get_SpriteFillBar(), false);
		this.removeChild(character.get_MPBar().get_SpriteFillBar(), false);
		_ComputerCharacters.remove(character);
	}
}
